import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

/**
 * 文件加密解密图形界面
 * 使用Swing实现简单的文件加密解密GUI
 */
public class FileEncryptionGUI extends JFrame {

    private JTextField sourceFileField;
    private JTextField destFileField;
    private JPasswordField passwordField;
    private JPasswordField confirmPasswordField;
    private JProgressBar progressBar;
    private JTextArea logArea;
    private JButton encryptButton;
    private JButton decryptButton;
    private JRadioButton methodStream;
    private JRadioButton methodDirect;
    private JRadioButton methodLarge;
    
    public FileEncryptionGUI() {
        setTitle("文件加密解密工具");
        setSize(600, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        
        // 创建主面板
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout(10, 10));
        mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
        
        // 创建表单面板
        JPanel formPanel = new JPanel();
        formPanel.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(5, 5, 5, 5);
        
        // 源文件选择
        gbc.gridx = 0;
        gbc.gridy = 0;
        formPanel.add(new JLabel("源文件:"), gbc);
        
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        sourceFileField = new JTextField(20);
        formPanel.add(sourceFileField, gbc);
        
        gbc.gridx = 2;
        gbc.weightx = 0.0;
        JButton browseSourceButton = new JButton("浏览...");
        formPanel.add(browseSourceButton, gbc);
        
        // 目标文件选择
        gbc.gridx = 0;
        gbc.gridy = 1;
        formPanel.add(new JLabel("目标文件:"), gbc);
        
        gbc.gridx = 1;
        gbc.weightx = 1.0;
        destFileField = new JTextField(20);
        formPanel.add(destFileField, gbc);
        
        gbc.gridx = 2;
        gbc.weightx = 0.0;
        JButton browseDestButton = new JButton("浏览...");
        formPanel.add(browseDestButton, gbc);
        
        // 密码输入
        gbc.gridx = 0;
        gbc.gridy = 2;
        formPanel.add(new JLabel("密码:"), gbc);
        
        gbc.gridx = 1;
        gbc.gridwidth = 2;
        passwordField = new JPasswordField(20);
        formPanel.add(passwordField, gbc);
        
        // 确认密码输入
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.gridwidth = 1;
        formPanel.add(new JLabel("确认密码:"), gbc);
        
        gbc.gridx = 1;
        gbc.gridwidth = 2;
        confirmPasswordField = new JPasswordField(20);
        formPanel.add(confirmPasswordField, gbc);
        
        // 加密方法选择
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.gridwidth = 1;
        formPanel.add(new JLabel("加密方法:"), gbc);
        
        gbc.gridx = 1;
        gbc.gridwidth = 2;
        JPanel methodPanel = new JPanel();
        methodPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        
        methodStream = new JRadioButton("流式处理");
        methodDirect = new JRadioButton("直接处理(小文件)");
        methodLarge = new JRadioButton("分块处理(大文件)");
        
        ButtonGroup methodGroup = new ButtonGroup();
        methodGroup.add(methodStream);
        methodGroup.add(methodDirect);
        methodGroup.add(methodLarge);
        
        methodStream.setSelected(true); // 默认选择流式处理
        
        methodPanel.add(methodStream);
        methodPanel.add(methodDirect);
        methodPanel.add(methodLarge);
        
        formPanel.add(methodPanel, gbc);
        
        // 按钮面板
        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.gridwidth = 3;
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
        
        encryptButton = new JButton("加密");
        decryptButton = new JButton("解密");
        JButton clearButton = new JButton("清除");
        
        buttonPanel.add(encryptButton);
        buttonPanel.add(decryptButton);
        buttonPanel.add(clearButton);
        
        formPanel.add(buttonPanel, gbc);
        
        // 进度条
        gbc.gridx = 0;
        gbc.gridy = 6;
        gbc.gridwidth = 3;
        progressBar = new JProgressBar(0, 100);
        progressBar.setStringPainted(true);
        formPanel.add(progressBar, gbc);
        
        // 日志区域
        logArea = new JTextArea(10, 40);
        logArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(logArea);
        
        // 添加组件到主面板
        mainPanel.add(formPanel, BorderLayout.NORTH);
        mainPanel.add(scrollPane, BorderLayout.CENTER);
        
        // 添加主面板到窗口
        add(mainPanel);
        
        // 添加事件监听器
        browseSourceButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                browseFile(sourceFileField);
            }
        });
        
        browseDestButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                browseFile(destFileField);
            }
        });
        
        encryptButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                encryptFile();
            }
        });
        
        decryptButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                decryptFile();
            }
        });
        
        clearButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                clearFields();
            }
        });
    }
    
    /**
     * 浏览文件
     * 
     * @param textField 要填充的文本字段
     */
    private void browseFile(JTextField textField) {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
        
        if (textField == sourceFileField) {
            fileChooser.setDialogTitle("选择源文件");
            fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        } else {
            fileChooser.setDialogTitle("选择目标文件");
            fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            
            // 如果是保存文件对话框，可以设置默认文件名
            if (sourceFileField.getText().length() > 0) {
                File sourceFile = new File(sourceFileField.getText());
                String defaultName = sourceFile.getName();
                
                if (encryptButton.isEnabled()) {
                    // 加密模式，添加.enc后缀
                    defaultName += ".enc";
                } else {
                    // 解密模式，去掉.enc后缀（如果有）
                    if (defaultName.endsWith(".enc")) {
                        defaultName = defaultName.substring(0, defaultName.length() - 4);
                    } else {
                        defaultName = "decrypted_" + defaultName;
                    }
                }
                
                fileChooser.setSelectedFile(new File(defaultName));
            }
        }
        
        int result = (textField == sourceFileField) ? 
                fileChooser.showOpenDialog(this) : 
                fileChooser.showSaveDialog(this);
        
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            textField.setText(selectedFile.getAbsolutePath());
        }
    }
    
    /**
     * 加密文件
     */
    private void encryptFile() {
        // 验证输入
        if (!validateInput(true)) {
            return;
        }
        
        // 获取输入值
        final String sourceFilePath = sourceFileField.getText();
        final String destFilePath = destFileField.getText();
        final String password = new String(passwordField.getPassword());
        
        // 禁用按钮，防止重复操作
        setComponentsEnabled(false);
        
        // 重置进度条
        progressBar.setValue(0);
        
        // 在后台线程中执行加密操作
        new SwingWorker<Boolean, Integer>() {
            @Override
            protected Boolean doInBackground() throws Exception {
                logMessage("开始加密文件: " + sourceFilePath);
                logMessage("目标文件: " + destFilePath);
                
                boolean result = false;
                
                try {
                    // 根据选择的方法执行加密
                    if (methodStream.isSelected()) {
                        logMessage("使用流式处理方法加密...");
                        result = FileEncryptionUtil.encryptFile(sourceFilePath, destFilePath, password);
                    } else if (methodDirect.isSelected()) {
                        logMessage("使用直接处理方法加密(适用于小文件)...");
                        result = FileEncryptionUtil.encryptFileWithCipher(sourceFilePath, destFilePath, password);
                    } else if (methodLarge.isSelected()) {
                        logMessage("使用分块处理方法加密(适用于大文件)...");
                        result = FileEncryptionUtil.encryptLargeFile(sourceFilePath, destFilePath, password);
                    }
                    
                    // 模拟进度更新
                    for (int i = 0; i <= 100; i += 10) {
                        publish(i);
                        Thread.sleep(100); // 延迟，模拟进度
                    }
                    
                    return result;
                } catch (Exception e) {
                    logMessage("加密过程中发生错误: " + e.getMessage());
                    e.printStackTrace();
                    return false;
                }
            }
            
            @Override
            protected void process(java.util.List<Integer> chunks) {
                // 更新进度条
                int latestProgress = chunks.get(chunks.size() - 1);
                progressBar.setValue(latestProgress);
            }
            
            @Override
            protected void done() {
                try {
                    boolean result = get();
                    if (result) {
                        logMessage("文件加密成功!");
                        JOptionPane.showMessageDialog(FileEncryptionGUI.this, 
                                "文件加密成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        logMessage("文件加密失败!");
                        JOptionPane.showMessageDialog(FileEncryptionGUI.this, 
                                "文件加密失败!", "错误", JOptionPane.ERROR_MESSAGE);
                    }
                } catch (Exception e) {
                    logMessage("加密过程中发生异常: " + e.getMessage());
                    JOptionPane.showMessageDialog(FileEncryptionGUI.this, 
                            "加密过程中发生异常: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                }
                
                // 重新启用按钮
                setComponentsEnabled(true);
                progressBar.setValue(100);
            }
        }.execute();
    }
    
    /**
     * 解密文件
     */
    private void decryptFile() {
        // 验证输入
        if (!validateInput(false)) {
            return;
        }
        
        // 获取输入值
        final String sourceFilePath = sourceFileField.getText();
        final String destFilePath = destFileField.getText();
        final String password = new String(passwordField.getPassword());
        
        // 禁用按钮，防止重复操作
        setComponentsEnabled(false);
        
        // 重置进度条
        progressBar.setValue(0);
        
        // 在后台线程中执行解密操作
        new SwingWorker<Boolean, Integer>() {
            @Override
            protected Boolean doInBackground() throws Exception {
                logMessage("开始解密文件: " + sourceFilePath);
                logMessage("目标文件: " + destFilePath);
                
                boolean result = false;
                
                try {
                    // 根据选择的方法执行解密
                    if (methodStream.isSelected()) {
                        logMessage("使用流式处理方法解密...");
                        result = FileEncryptionUtil.decryptFile(sourceFilePath, destFilePath, password);
                    } else if (methodDirect.isSelected()) {
                        logMessage("使用直接处理方法解密(适用于小文件)...");
                        result = FileEncryptionUtil.decryptFileWithCipher(sourceFilePath, destFilePath, password);
                    } else if (methodLarge.isSelected()) {
                        logMessage("使用分块处理方法解密(适用于大文件)...");
                        result = FileEncryptionUtil.decryptLargeFile(sourceFilePath, destFilePath, password);
                    }
                    
                    // 模拟进度更新
                    for (int i = 0; i <= 100; i += 10) {
                        publish(i);
                        Thread.sleep(100); // 延迟，模拟进度
                    }
                    
                    return result;
                } catch (Exception e) {
                    logMessage("解密过程中发生错误: " + e.getMessage());
                    e.printStackTrace();
                    return false;
                }
            }
            
            @Override
            protected void process(java.util.List<Integer> chunks) {
                // 更新进度条
                int latestProgress = chunks.get(chunks.size() - 1);
                progressBar.setValue(latestProgress);
            }
            
            @Override
            protected void done() {
                try {
                    boolean result = get();
                    if (result) {
                        logMessage("文件解密成功!");
                        JOptionPane.showMessageDialog(FileEncryptionGUI.this, 
                                "文件解密成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        logMessage("文件解密失败! 可能是密码错误或文件已损坏。");
                        JOptionPane.showMessageDialog(FileEncryptionGUI.this, 
                                "文件解密失败! 可能是密码错误或文件已损坏。", "错误", JOptionPane.ERROR_MESSAGE);
                    }
                } catch (Exception e) {
                    logMessage("解密过程中发生异常: " + e.getMessage());
                    JOptionPane.showMessageDialog(FileEncryptionGUI.this, 
                            "解密过程中发生异常: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                }
                
                // 重新启用按钮
                setComponentsEnabled(true);
                progressBar.setValue(100);
            }
        }.execute();
    }
    
    /**
     * 验证输入
     * 
     * @param isEncrypt 是否是加密操作
     * @return 输入是否有效
     */
    private boolean validateInput(boolean isEncrypt) {
        // 检查源文件
        if (sourceFileField.getText().isEmpty()) {
            JOptionPane.showMessageDialog(this, "请选择源文件!", "错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        
        File sourceFile = new File(sourceFileField.getText());
        if (!sourceFile.exists() || !sourceFile.isFile()) {
            JOptionPane.showMessageDialog(this, "源文件不存在或不是有效的文件!", "错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        
        // 检查目标文件
        if (destFileField.getText().isEmpty()) {
            JOptionPane.showMessageDialog(this, "请选择目标文件!", "错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        
        // 检查目标文件是否已存在
        File destFile = new File(destFileField.getText());
        if (destFile.exists()) {
            int result = JOptionPane.showConfirmDialog(this, 
                    "目标文件已存在，是否覆盖?", "确认", JOptionPane.YES_NO_OPTION);
            if (result != JOptionPane.YES_OPTION) {
                return false;
            }
        }
        
        // 检查密码
        if (new String(passwordField.getPassword()).isEmpty()) {
            JOptionPane.showMessageDialog(this, "请输入密码!", "错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        
        // 如果是加密操作，检查确认密码
        if (isEncrypt) {
            String password = new String(passwordField.getPassword());
            String confirmPassword = new String(confirmPasswordField.getPassword());
            
            if (password.length() < 8) {
                JOptionPane.showMessageDialog(this, "密码长度必须至少为8个字符!", "错误", JOptionPane.ERROR_MESSAGE);
                return false;
            }
            
            if (!password.equals(confirmPassword)) {
                JOptionPane.showMessageDialog(this, "两次输入的密码不一致!", "错误", JOptionPane.ERROR_MESSAGE);
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 清除所有字段
     */
    private void clearFields() {
        sourceFileField.setText("");
        destFileField.setText("");
        passwordField.setText("");
        confirmPasswordField.setText("");
        progressBar.setValue(0);
        logArea.setText("");
    }
    
    /**
     * 设置组件启用状态
     * 
     * @param enabled 是否启用
     */
    private void setComponentsEnabled(boolean enabled) {
        sourceFileField.setEnabled(enabled);
        destFileField.setEnabled(enabled);
        passwordField.setEnabled(enabled);
        confirmPasswordField.setEnabled(enabled);
        encryptButton.setEnabled(enabled);
        decryptButton.setEnabled(enabled);
        methodStream.setEnabled(enabled);
        methodDirect.setEnabled(enabled);
        methodLarge.setEnabled(enabled);
    }
    
    /**
     * 添加日志消息
     * 
     * @param message 消息内容
     */
    private void logMessage(String message) {
        logArea.append(message + "\n");
        // 滚动到最新消息
        logArea.setCaretPosition(logArea.getDocument().getLength());
    }
    
    /**
     * 主方法
     * 
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 设置界面风格为系统风格
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        // 启动GUI
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new FileEncryptionGUI().setVisible(true);
            }
        });
    }
}